﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;

namespace Awesome.Library.Cryptography {

	public class RSACrypto {

		public static string EncryptString( string inputString, int dwKeySize, string xmlString ) {
			// TODO: Add Proper Exception Handlers
			RSACryptoServiceProvider rsaCryptoServiceProvider = new RSACryptoServiceProvider( dwKeySize );
			rsaCryptoServiceProvider.FromXmlString( xmlString );
			int keySize = dwKeySize / 8;
			byte[] bytes = Encoding.UTF8.GetBytes( inputString );
			// The hash function in use by the .NET RSACryptoServiceProvider here 
			// is SHA1
			// int maxLength = ( keySize ) - 2 - 
			//              ( 2 * SHA1.Create().ComputeHash( rawBytes ).Length );
			int maxLength = keySize - 42;
			int dataLength = bytes.Length;
			int iterations = dataLength / maxLength;
			StringBuilder stringBuilder = new StringBuilder();
			for ( int i = 0; i <= iterations; i++ ) {
				byte[] tempBytes = new byte[( dataLength - maxLength * i > maxLength ) ? maxLength : dataLength - maxLength * i];
				Buffer.BlockCopy( bytes, maxLength * i, tempBytes, 0, tempBytes.Length );
				byte[] encryptedBytes = rsaCryptoServiceProvider.Encrypt( tempBytes, true );
				// Be aware the RSACryptoServiceProvider reverses the order of 
				// encrypted bytes. It does this after encryption and before 
				// decryption. If you do not require compatibility with Microsoft 
				// Cryptographic API (CAPI) and/or other vendors. Comment out the 
				// next line and the corresponding one in the DecryptString function.
				Array.Reverse( encryptedBytes );
				// Why convert to base 64?
				// Because it is the largest power-of-two base printable using only 
				// ASCII characters
				stringBuilder.Append( Convert.ToBase64String( encryptedBytes ) );
			}
			return stringBuilder.ToString();
		}

		public static string DecryptString( string inputString, int dwKeySize, string xmlString ) {
			// TODO: Add Proper Exception Handlers
			RSACryptoServiceProvider rsaCryptoServiceProvider = new RSACryptoServiceProvider( dwKeySize );
			rsaCryptoServiceProvider.FromXmlString( xmlString );
			int base64BlockSize = ( ( dwKeySize / 8 ) % 3 != 0 ) ? ( ( ( dwKeySize / 8 ) / 3 ) * 4 ) + 4 : ( ( dwKeySize / 8 ) / 3 ) * 4;
			int iterations = inputString.Length / base64BlockSize;
			List<byte> arrayList = new List<byte>();
			for ( int i = 0; i < iterations; i++ ) {
				byte[] encryptedBytes = Convert.FromBase64String( inputString.Substring( base64BlockSize * i, base64BlockSize ) );
				// Be aware the RSACryptoServiceProvider reverses the order of 
				// encrypted bytes after encryption and before decryption.
				// If you do not require compatibility with Microsoft Cryptographic 
				// API (CAPI) and/or other vendors.
				// Comment out the next line and the corresponding one in the 
				// EncryptString function.
				Array.Reverse( encryptedBytes );
				arrayList.AddRange( rsaCryptoServiceProvider.Decrypt( encryptedBytes, true ) );
			}
			return Encoding.UTF8.GetString( arrayList.ToArray() );
		}
	}

}
